/**
 * 产品+组合 业务组件 树形结构(不支持筛选)
 * by zhangxinyue
 * create 2020-08-12
 */
import React from 'react';
import { connect } from 'dva';
import PropTypes from 'prop-types';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { TreeSelect, Tooltip } from 'antd';
import { FormItemLayout, NoLableLayout } from '../../form/formPub.js';

class ProductGroupTreeC extends React.PureComponent {
  // props默认值
  static defaultProps = {
    title: '组合',
    placeholder: '请选择组合',
    helper: '',
    onChange: () => {},
    onRef: () => {}, // 本组件的引用
    width: '100%',
    maxTagCount: 0,
    productId: undefined, // 默认无产品ID，获取所有产品下的组合
    ralation: false, // 默认单独展示，无关联关系
    rules: undefined, // 默认无校验规则
    multiple: true, // 默认支持多选
    formItemLayout: FormItemLayout, // 设置form表单布局默认值
    allowClear: true, // 默认可删除
    authority: 'read', // 默认是读权限
    disabled: false, // 默认不禁用
    treeCheckable: false, // 默认不显示
    maatApi: false, // 默认什么环境下就用什么该环境的组合
    labalWrap: false,
  };

  constructor(props) {
    super(props);
    this.state = {
      groupDS: undefined, // 与产品有关联关系是的数据源
      treeExpandedKeys: [], // 记录树展开的节点（解决数据刷新时，树节点未默认展开问题）
    };
  }

  componentDidMount() {
    // 父组件对本组件的引用
    this.props.onRef(this);

    if (!this.props.ralation) {
      // 调用接口，获取产品+组合数据
      this.getProductGroup(this.props.productId, this.props.authority, (args) => {
        this.setState({
          groupDS: args,
        });
      });
    } else {
      if (this.props.productId) {
        this.initSeletData(this.props.productId, this.props.authority);
      }
    }
  }

  // 遍历树形结构，找出所有非叶子节点
  findParentKey = (data, keys) => {
    if (data && data.length > 0) {
      data.forEach((item) => {
        if (item && item.children && item.children.length > 0) {
          keys.push(item.key);
          this.findParentKey(item.children, keys);
        }
      });
    }
  };

  // 初始化下拉数据
  initSeletData = (productId, authority) => {
    // 调用接口，获取产品下的组合数据
    this.getProductGroup(productId, authority, (args) => {
      this.setState({
        groupDS: args,
      });
      // 找出所有父节点，并展开
      let keys = [];
      this.findParentKey(args, keys);
      this.setState({
        treeExpandedKeys: keys,
      });
    });
  };

  UNSAFE_componentWillReceiveProps(nextProps) {
    // 响应外部组件产品切换场景
    if (this.props.ralation && this.props.productId != nextProps.productId) {
      // 当ralation为true时，productId==undefined，证明未选中任何产品，组合下拉内容置空
      if (nextProps.productId === undefined) {
        this.setState({
          groupDS: [{ value: 'blank', title: '请先选择产品', disabled: true }],
        });
      } else {
        this.setState({
          groupDS: undefined,
        });
        this.initSeletData(nextProps.productId, nextProps.authority);
      }
    }
  }

  // 调用接口，获取产品+组合树形结构
  getProductGroup = (productId, authority, callback) => {
    // 当设置了产品ID时，获取产品下的组合
    if (productId) {
      this.props.dispatch({
        type: 'productAGroupM/getProductGroup',
        payload: {
          rootId: productId,
          authority: authority,
          maatApi: this.props.maatApi,
        },
        callback: callback,
      });
    } else {
      // 当未设置产品ID时，获取全量信息
      this.props.dispatch({
        type: 'productAGroupM/getProductGroup',
        payload: {
          authority: authority,
          maatApi: this.props.maatApi,
        },
      });
    }
  };

  // 非初始化状态下更改下拉选项(供父组件调用)
  setSelect = (value) => {
    const valueF = {};
    valueF[this.props.dataIndex] = value;
    this.props.form.setFieldsValue(valueF);

    // 响应变更事件
    this.onChange(value);
  };

  // 树节点展开事件，解决数据刷新时，树节点未默认展开问题
  onTreeExpand = (expandedKeys) => {
    this.setState({
      treeExpandedKeys: expandedKeys,
    });
  };

  // 根据key值，遍历树节点
  findNode = (data, key, node) => {
    data.forEach((element) => {
      if (element.value === key) {
        node.push(element);
      }
      if (element.children) {
        this.findNode(element.children, key, node);
      }
    });
  };

  // 选中树节点变更事件
  onChange = (e) => {
    if (e == undefined || e.length == 0) {
      this.props.onChange(undefined);
      return;
    }

    let args = { key: e, info: undefined };
    let ds = this.props.ralation ? this.state.groupDS : this.props.productAGroupM.productGroup;
    // 多选
    if (this.props.multiple) {
      let info = [];
      e.forEach((element) => {
        let temp = [];
        this.findNode(ds, element, temp);
        info.push(temp[0]);
      });
      args.info = info;
    } else {
      // 单选
      let temp = [];
      this.findNode(ds, e, temp);
      args.info = temp[0];
    }
    this.props.onChange(args);
  };

  // 模糊查询，匹配Name或code
  filterTreeNode = (inputValue, treeNode) => {
    let portfolioCode = treeNode.props.portfolioCode;
    let portfolioName = treeNode.props.portfolioName;
    return portfolioCode.indexOf(inputValue) > -1 || portfolioName.indexOf(inputValue) > -1;
  };

  render() {
    const {
      labalWrap,
      form,
      title,
      dataIndex,
      initialValue,
      placeholder,
      helper,
      maxTagCount,
      width,
      ralation,
      multiple,
      rules,
      formItemLayout,
      allowClear,
      disabled,
      treeCheckable,
    } = this.props;
    const { getFieldDecorator } = form;

    return (
      <Form.Item
        className={labalWrap ? 'labalWrap' : ''}
        labelCol={title ? formItemLayout.labelCol : NoLableLayout.labelCol}
        wrapperCol={title ? formItemLayout.wrapperCol : NoLableLayout.wrapperCol}
        label={
          title ? (
            helper ? (
              <span>
                {title}&nbsp;
                <Tooltip title={helper}>
                  <QuestionCircleOutlined />
                </Tooltip>
              </span>
            ) : (
              <span>{title}</span>
            )
          ) : undefined
        }
      >
        {getFieldDecorator(dataIndex, {
          initialValue,
          rules: !!rules ? rules : [],
        })(
          <TreeSelect
            getPopupContainer={(triggerNode) => triggerNode.parentNode}
            style={{ width: width }}
            maxTagCount={maxTagCount}
            placeholder={placeholder} // 占位符
            onChange={this.onChange} // 选中树节点时调用此函数
            treeData={
              // 数据源
              ralation
                ? this.state.groupDS != undefined
                  ? this.state.groupDS
                  : [{ value: 'blank', title: '正在加载中...', disabled: true }]
                : this.props.productAGroupM.productGroup != undefined
                ? this.props.productAGroupM.productGroup
                : [{ value: 'blank', title: '正在加载中...', disabled: true }]
            }
            multiple={multiple} // 支持多选（当设置 treeCheckable 时自动变为 true）
            treeCheckable={treeCheckable} // 设置checkbox的显示或隐藏
            showCheckedStrategy={treeCheckable ? TreeSelect.SHOW_ALL : TreeSelect.SHOW_CHILD}
            allowClear={allowClear} // 显示清除按钮
            treeDefaultExpandAll={true} // 默认展开所有树节点（仅初始化时生效）
            treeExpandedKeys={ralation ? this.state.treeExpandedKeys : undefined} // 设置树节点展开
            onTreeExpand={ralation ? this.onTreeExpand : undefined} // 树节点展开调用事件
            dropdownMatchSelectWidth={true} // 下拉菜单和选择器同宽
            disabled={disabled}
            showSearch={true} // 支持模糊查询
            filterTreeNode={this.filterTreeNode}
          />,
        )}
      </Form.Item>
    );
  }
}

// props类型
ProductGroupTreeC.propsTypes = {
  form: PropTypes.object, // form对象
  title: PropTypes.string, // 显示名称
  dataIndex: PropTypes.string, // Form识别的Item ID
  initialValue: PropTypes.oneOfType([
    // 初始默认值
    PropTypes.string, // 单选模式
    PropTypes.array, // 多选模式
  ]),
  rules: PropTypes.object, // 校验规则
  placeholder: PropTypes.string, // 占位符
  onChange: PropTypes.func, // 输入框内容变化时的回调
  helper: PropTypes.oneOfType([
    // 提示帮助信息
    PropTypes.string,
    PropTypes.element,
  ]),
  onRef: PropTypes.func, // 本组件的引用（可用来父组件调用内部方法）
  maxTagCount: PropTypes.number,
  productId: PropTypes.string, // 产品ID（在ralation为true时，设置productId生效）
  ralation: PropTypes.bool, // 设置是否与产品有关联关系
  multiple: PropTypes.bool, // 是否支持多选
  formItemLayout: PropTypes.object, // 设置表单布局
  allowClear: PropTypes.bool, // 设置是否可删除
  authority: PropTypes.oneOf(['read', 'write']), // 设置权限类型
  disabled: PropTypes.bool, // 是否禁用
  treeCheckable: PropTypes.bool, // 是否显示checkbox
  maatApi: PropTypes.bool, // 正常情况下，在哪个环境下，就访问哪个环境的组合，
  // 但在投资建议书模块中，被引用到资管环境时，该组件的接口仍然要访问maat环境中的组合（而不是资管环境中组合），此时需要在接口前添加maat前缀
};

export default connect(({ productAGroupM, loading }) => ({ productAGroupM, loading }))(ProductGroupTreeC);
